package fasttemplate

import (
	"fmt"
	"github.com/valyala/fasttemplate"
	"io"
	"log"
	"net/url"
)

/*
可以使用fasttemplate完成strings.Replace和fmt.Sprintf的任务，而且fasttemplate灵活性更高。代码清晰易懂，值得一看。

吐槽：关于命名，Execute()方法里面使用stdTagFunc，ExecuteStd()方法里面使用keepUnknownTagFunc方法。我想是不是把stdTagFunc改名为defaultTagFunc好一点？


*/

func Run() {

	//占位符中间内部不要加空格！！！
	template := `name: {{name}}
age: {{age}}`

	//创建模板，指定占位符
	t := fasttemplate.New(template, "{{", "}}")
	s1 := t.ExecuteString(map[string]interface{}{
		"name": "dj",
		"age":  "18",
	})
	//ExecuteString()方法使用stdTagFunc，即直接将未识别的tag替换成空字符串。如果想保留未识别的tag，改为调用ExecuteStringStd()方法即可。该方法遇到未识别的tag会保留：
	s2 := t.ExecuteStringStd(map[string]interface{}{
		"name": "hjw",
		"age":  "20",
	})
	fmt.Println(s1)
	fmt.Println(s2)

	//fasttemplate针对每个占位符都会调用一次TagFunc函数，tag即占位符的名称
	s3 := t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
		switch tag {
		case "name":
			return w.Write([]byte("dj"))
		case "age":
			return w.Write([]byte("18"))
		default:
			return 0, nil
		}
	})

	fmt.Println(s3)

	//如果模板中的tag在参数map[string]interface{}中不存在，有两种处理方式：
	//
	//直接忽略，相当于替换成了空字符串""。标准的stdTagFunc就是这样处理的；
	//保留原始tag。keepUnknownTagFunc就是做这个事情的。

}

func ExampleTemplate() {
	template := "http://{{host}}/?foo={{bar}}{{bar}}&q={{query}}&baz={{baz}}"
	t := fasttemplate.New(template, "{{", "}}")

	// Substitution map.
	// Since "baz" tag is missing in the map, it will be substituted
	// by an empty string.
	m := map[string]interface{}{
		"host": "google.com",     // string - convenient
		"bar":  []byte("foobar"), // byte slice - the fastest

		// TagFunc - flexible value. TagFunc is called only if the given
		// tag exists in the template.
		"query": fasttemplate.TagFunc(func(w io.Writer, tag string) (int, error) {
			return w.Write([]byte(url.QueryEscape(tag + "=world")))
		}),
	}

	s := t.ExecuteString(m)
	fmt.Printf("%s", s)

	// Output:
	// http://google.com/?foo=foobarfoobar&q=query%3Dworld&baz=
}

func ExampleTagFunc() {
	template := "foo[baz]bar"
	t, err := fasttemplate.NewTemplate(template, "[", "]")
	if err != nil {
		log.Fatalf("unexpected error when parsing template: %s", err)
	}

	bazSlice := [][]byte{[]byte("123"), []byte("456"), []byte("789")}
	m := map[string]interface{}{
		// Always wrap the function into TagFunc.
		//
		// "baz" tag function writes bazSlice contents into w.
		"baz": fasttemplate.TagFunc(func(w io.Writer, tag string) (int, error) {
			var nn int
			for _, x := range bazSlice {
				n, err := w.Write(x)
				if err != nil {
					return nn, err
				}
				nn += n
			}
			return nn, nil
		}),
	}

	s := t.ExecuteString(m)
	fmt.Printf("%s", s)

	// Output:
	// foo123456789bar
}

func ExampleTemplate_ExecuteFuncString() {
	template := "Hello, [user]! You won [prize]!!! [foobar]"
	t, err := fasttemplate.NewTemplate(template, "[", "]")
	if err != nil {
		log.Fatalf("unexpected error when parsing template: %s", err)
	}
	s := t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
		switch tag {
		case "user":
			return w.Write([]byte("John"))
		case "prize":
			return w.Write([]byte("$100500"))
		default:
			return w.Write([]byte(fmt.Sprintf("[unknown tag %q]", tag)))
		}
	})
	fmt.Printf("%s", s)

	// Output:
	// Hello, John! You won $100500!!! [unknown tag "foobar"]
}
